#pragma once
#include "../opengl/opengl.hpp"

class Pipeline {
public:
    Pipeline() = default;
    Pipeline(const Pipeline &) = delete;
    Pipeline &operator=(const Pipeline &) = delete;

    void update() { active = false; }

    void activate() {
        if (!active) {
            active = true;
            if (depthTest.enabled) {
                opengl::api::glEnable(opengl::depth_test);
                opengl::api::glDepthFunc(depthTest.func);
                opengl::api::glDepthMask(depthTest.mask);
            } else {
                opengl::api::glDisable(opengl::depth_test);
            }
            if (stencilTest.enabled) {
                opengl::api::glEnable(opengl::stencil_test);
                opengl::api::glStencilFunc(stencilTest.func, stencilTest.ref, stencilTest.mask);
            } else {
                opengl::api::glDisable(opengl::stencil_test);
            }
            if (scissorTest.enabled) {
                opengl::api::glEnable(opengl::scissor_test);
                opengl::api::glScissor(scissorTest.x, scissorTest.y, scissorTest.width, scissorTest.height);
            } else {
                opengl::api::glDisable(opengl::scissor_test);
            }
            if (culling.enabled) {
                opengl::api::glEnable(opengl::cull_face);
                opengl::api::glCullFace(culling.mode);
            } else {
                opengl::api::glDisable(opengl::cull_face);
            }
        }
    };
    void deactivate() {
        if (active) {
            active = false;
            opengl::api::glDisable(opengl::depth_test);
            opengl::api::glDisable(opengl::stencil_test);
            opengl::api::glDisable(opengl::scissor_test);
            opengl::api::glDisable(opengl::cull_face);
            // opengl::api::glDisable(opengl::blend); // Blending is not
        }
    };

    void draw(opengl::u32 count, opengl::i32 start = 0) const { opengl::api::glDrawArrays(drawMode, start, count); }
    void drawIndexed(opengl::u32 count, opengl::i32 start = 0, opengl::u32 indexType = opengl::type_u32) {
        opengl::api::glDrawElements(drawMode, count, indexType, nullptr);
    }

private:
    bool active{false};
    opengl::u32 drawMode{opengl::mode_triangles};

public:
    struct {
        bool enabled{false};
        opengl::u8 mask{0xFF};
        opengl::u32 func{opengl::cmp_less};
    } depthTest;
    struct {
        bool enabled{false};
        opengl::u32 func{opengl::cmp_always};
        opengl::i32 ref{0};
        opengl::u32 mask{0xFFFFFFFF};
    } stencilTest;
    struct {
        bool enabled{false};
        opengl::i32 x{0};
        opengl::i32 y{0};
        opengl::i32 width{0};
        opengl::i32 height{0};
    } scissorTest;
    struct {
        bool enabled{false};
        opengl::u32 mode{opengl::mode_back};
    } culling;
    // struct {
    //     bool enabled{false};
    //     opengl::u32 srcRGB{opengl::blend_one};
    //     opengl::u32 dstRGB{opengl::blend_zero};
    //     opengl::u32 srcAlpha{opengl::blend_one};
    //     opengl::u32 dstAlpha{opengl::blend_zero};
    // } blending;
};